/*
 * Created on Dec 8, 2003
 *
 * To change the template for this generated file go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
package net.israfil.foundation.valuemodel;

import java.util.HashMap;
import java.util.Map;

import net.israfil.foundation.dynamic.DynamicUtil;


/**
 * @author cgruber
 *
 * To change the template for this generated type comment go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
public class ValueHolder<E> implements MutableValue<E> {

    private E _value = null;
    private Map<Integer, ObserverHolder> _observers = new HashMap<Integer, ObserverHolder>();
    private Map<Integer, VetoerHolder> _vetoers = new HashMap<Integer, VetoerHolder>();

	public ValueHolder(E o) {
		set(o); 
	}
        
    protected ValueHolder() { }

	public E get() {
		return _value;
	}

    public void set(E newValue) {
        boolean approved = true;
        E oldValue = _value;
        for (VetoerHolder vetoer : _vetoers.values()) {
        	approved &= vetoer.evaluate(this, oldValue, newValue);
        }
        
        if (!approved) return;
        else _value = newValue;
        for (ObserverHolder observer : _observers.values()) {
            observer.notify(this, oldValue, newValue);
        }
        
    }

	/**
	 * @see org.israfil.maveric.Observable#addObserver(java.lang.Object, java.lang.String)
	 */
	public void addObservers(String callback, Object ... observers) {
    	for (Object observer : observers) {
    		_observers.put(observer.hashCode(),new ObserverHolder(observer,callback));
    	}
	}

	/**
     * @see org.israfil.maveric.Observable#removeObserver(java.lang.Object)
	 */
	public void removeObservers(Object ... observers) {
    	for (Object observer : observers) {
    		_observers.remove(observer.hashCode());
    	}
	}
    /**
     * @see org.israfil.maveric.Vetoable#addVetoer(java.lang.Object, java.lang.String)
     */
    public void addVetoers(String callback, Object ... vetoers) {
    	for (Object vetoer : vetoers) {
    		_vetoers.put(vetoer.hashCode(),new VetoerHolder(vetoer,callback));
    	}
    }

    /**
     * @see org.israfil.maveric.Vetoable#removeVetoer(java.lang.Object)
     */
    public void removeVetoers(Object ... vetoers) {
    	for (Object vetoer : vetoers) {
    		_vetoers.remove(vetoer.hashCode());
    	}
    }

    protected class CallbackObjectHolder {
        public final Object receiver;
        protected final String callback; 
        public CallbackObjectHolder(Object receiver, String callback) {
            this.receiver = receiver;
            this.callback = callback;
        }
    }
    protected class ObserverHolder extends CallbackObjectHolder {
        public ObserverHolder(Object observer, String callback) { super(observer, callback); }
        public void notify(Object notifier, Object oldValue, Object newValue) {
            DynamicUtil.performOn(receiver,callback,new Object[]{notifier, oldValue , newValue});
        }
    }
    protected class VetoerHolder extends CallbackObjectHolder {
        public VetoerHolder(Object vetoer, String callback) { super(vetoer, callback); }
        public Boolean evaluate(Object notifier, Object oldValue, Object newValue) {
            Boolean result = (Boolean)DynamicUtil.performOn(receiver,callback,new Object[]{notifier,oldValue,newValue});
            return (result == null) ? true : result.booleanValue();
        }
    }
}
